package session

import (
    "github.com/pkg/errors"
    "io"
    "log"
    "net"
    "xncc_client/msg_list"
    "xncc_client/util"
)

type TcpSession struct {
    Connection net.Conn
    Id         int32
}

func NewSession(serverAddr string) *TcpSession {
    conn, err := net.Dial("tcp", serverAddr)
    if err != nil {
        log.Printf("connect server failed, err=[%s]\n", err)
        return nil
    }
    return &TcpSession{
        Connection: conn,
        Id:         util.Generator.ID(),
    }
}

func (s *TcpSession) receiveHeader() *msg_list.XNCCHeader {
    h := &msg_list.XNCCHeader{}
    headerBytes := make([]byte, h.Len())
    _, err := io.ReadFull(s.Connection, headerBytes)
    if err != nil {
        if err == io.EOF {
            log.Println("peer close")
            panic("peer close")
            return nil
        } else {
            log.Println("read failed")
            return nil
        }
    }
    h.Decode(headerBytes)
    return h
}

func (s *TcpSession) ReceiveMsg() (*msg_list.MsgWrapper, error) {
    h := s.receiveHeader()
    if h != nil {
        bodyBytes := make([]byte, h.BodyLen)
        _, err := io.ReadFull(s.Connection, bodyBytes)
        if err != nil {
            if err == io.EOF {
                log.Println("peer close")
                panic("peer close")
                return nil, err
            } else {
                log.Println("read failed")
                return nil, err
            }
        } else {
            msgw := &msg_list.MsgWrapper{
                ProtoId: h.ProtoId,
                Msg:     msg_list.CreateMsg(h.ProtoId),
            }
            return msgw, nil
        }
    } else {
        return nil, errors.New("receive failed")
    }
}

func (s *TcpSession) SendMsg(msg msg_list.XNCCMsg) {
    wData, err1 := msg.Encode()
    if err1 != nil {
        log.Println("msg encode error")
        return
    }

    n := len(wData)
    wN := 0
    var err error = nil
    for {
        if n > 0 {
            wN, err = s.Connection.Write(wData)
            if err != nil {
                log.Printf("write data error [%s]\n", err)
                break
            } else {
                log.Printf("write data %v\n", wData)
            }
        } else {
            log.Printf("will send byte len is error %v\n", wData)
            break
        }
        n = n - wN
        wData = wData[wN:]
    }
}
